﻿using RockBus.Monitoring.DataContracts.Configuration;
using RockBus.Monitoring.DataContracts;
using RockBus.Utilities;
using System;
using System.Linq;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;

namespace RockBus.Monitoring
{
    /// <summary>
    /// Base class for the performance counter collectors.
    /// </summary>
    public abstract class PerformanceCounterCollectorBase
    {
        protected PerformanceCounterCollectorBase(PerformanceCounterConfigurationBase pcc, int bufferSize)
        {
            this.RoundRobinBufferDictionary = new ConcurrentDictionary<Tuple<string, string>, Tuple<PerformanceCounterInstance, RoundRobinBuffer>>();
            PerformanceCounterConfigurationBase = pcc;
            if (pcc.AggregationType == AggregationTypeEnum.LastValue)
            {
                this.BufferSize = 1;
            }
            else
            {
                this.BufferSize = bufferSize;
            }
        }

        /// <summary>
        /// Holds the base configuration for the performance counter to be collected.
        /// </summary>
        public PerformanceCounterConfigurationBase PerformanceCounterConfigurationBase { get; protected set; }

        public int BufferSize { get; private set; }

        /// <summary>
        /// Holds the performance counter (instance) value buffer(s).
        /// </summary>
        public ConcurrentDictionary<Tuple<string, string>, Tuple<PerformanceCounterInstance, RoundRobinBuffer>> RoundRobinBufferDictionary { get; private set; }

        protected void AddCounterSample(string counterName, string instanceName, CounterSample counterSample)
        {
            var key = new Tuple<string, string>(counterName, instanceName);
            if (!this.RoundRobinBufferDictionary.ContainsKey(key))
            {
                this.RoundRobinBufferDictionary.TryAdd(key,
                    new Tuple<PerformanceCounterInstance, RoundRobinBuffer>(
                        new PerformanceCounterInstance(this.PerformanceCounterConfigurationBase.CategoryName, counterName, instanceName, 0.0D),
                        new RoundRobinBuffer(this.BufferSize)));
            }

            var tuple = this.RoundRobinBufferDictionary[key];
            tuple.Item2.AddCounterSample(counterSample);
            tuple.Item1.Value = tuple.Item2.GetValue(this.PerformanceCounterConfigurationBase.AggregationType.Value);
        }

        public IEnumerable<PerformanceCounterInstance> GetSnapshot()
        {
            return this.RoundRobinBufferDictionary.Values.Select((t) => t.Item1).Clone();
        }

        public abstract void Collect();
    }
}